﻿#requires –version 2.0

Function Test-WSUSClient {

#region Help

<#
.SYNOPSIS
	Automation Script.
.DESCRIPTION
	Script for automating a process.
.NOTES
	VERSION:    2.4.3
	AUTHOR:     Levon Becker
	EMAIL:      PowerShell.Guru@BonusBits.com 
	ENV:        Powershell v2.0, CLR 4.0+, PowerCLI 4.1+
	TOOLS:      PowerGUI Script Editor
.INPUTS
	ComputerName    Single Hostname
	List            List of Hostnames
	FileName        File with List of Hostnames
	FileBrowser     File with List of Hostnames
	
	DEFAULT FILENAME PATH
	---------------------
	HOSTLISTS
	%USERPROFILE%\Documents\HostList
.OUTPUTS
	DEFAULT PATHS
	-------------
	RESULTS
	%USERPROFILE%\Documents\Results\Test-WSUSClient
	
	LOGS
	%USERPROFILE%\Documents\Logs\Test-WSUSClient
	+---History
	+---JobData
	+---Latest
	+---WIP
.EXAMPLE
	Test-WSUSClient -ComputerName server01 
	Patch a single computer.
.EXAMPLE
	Install-Patches server01 
	Patch a single computer.
	The ComputerName parameter is in position 0 so it can be left off for a
	single computer.
.EXAMPLE
	Test-WSUSClient -List server01,server02
	Test a list of hostnames comma separated without spaces.
.EXAMPLE
	Test-WSUSClient -List $MyHostList 
	Test a list of hostnames from an already created array variable.
	i.e. $MyHostList = @("server01","server02","server03")
.EXAMPLE
	Test-WSUSClient -FileBrowser 
	This switch will launch a separate file browser window.
	In the window you can browse and select a text or csv file from anywhere
	accessible by the local computer that has a list of host names.
	The host names need to be listed one per line or comma separated.
	This list of system names will be used to perform the script tasks for 
	each host in the list.
.EXAMPLE
	Test-WSUSClient -FileBrowser -SkipAllVmware
	FileBrowser:
		This switch will launch a separate file browser window.
		In the window you can browse and select a text or csv file from anywhere
		accessible by the local computer that has a list of host names.
		The host names need to be listed one per line or comma separated.
		This list of system names will be used to perform the script tasks for 
		each host in the list.
	SkipAllVmware:
		This switch will skip all Vmware tasks and requirements.
.EXAMPLE
	Test-WSUSClient -FileBrowser -SkipOutGrid -SkipAllVmware
	FileBrowser:
		This switch will launch a separate file browser window.
		In the window you can browse and select a text or csv file from anywhere
		accessible by the local computer that has a list of host names.
		The host names need to be listed one per line or comma separated.
		This list of system names will be used to perform the script tasks for 
		each host in the list.
	SkipOutGrid:
		This switch will skip the results poppup windows at the end.
	SkipAllVmware:
		This switch will skip all Vmware tasks and requirements.
.EXAMPLE
	Test-WSUSClient -FileBrowser -SkipPolicyUpdate -SkipSettingsReset
	FileBrowser:
		This switch will launch a separate file browser window.
		In the window you can browse and select a text or csv file from anywhere
		accessible by the local computer that has a list of host names.
		The host names need to be listed one per line or comma separated.
		This list of system names will be used to perform the script tasks for 
		each host in the list.
	SkipPolicyUpdate:
		This switch will skip the task to update the computer and user policies 
		on the remote computers.
	SkipSettingsReset:
		This switch will skip the task to reset the Windows Update service 
		settings and re-register the remote system with the WSUS server.
.PARAMETER ComputerName
	Short name of Windows host to patch
	Do not use FQDN 
.PARAMETER List
	A PowerShell array List of servers to patch or comma separated list of host
	names to perform the script tasks on.
	-List server01,server02
	@("server1", "server2") will work as well
	Do not use FQDN
.PARAMETER FileName
	Text or Comma Delimited file with a List of servers to patch
	One host per line
	Do not use FQDN
.PARAMETER FileBrowser
	This switch will launch a separate file browser window.
	In the window you can browse and select a text or csv file from anywhere
	accessible by the local computer that has a list of host names.
	The host names need to be listed one per line or comma separated.
	This list of system names will be used to perform the script tasks for 
	each host in the list.
.PARAMETER MaxJobs
	Maximum amount of background jobs to run simultaneously. 
	Adjust depending on how much memory and load the localhost can handle.
	Because the entire task is rather quick it's better to keep this number 
	low for overall speed.
	It's not recommended to set higher than 400.
	Default = 100
.PARAMETER JobQueTimeout
	Maximum amount of time in seconds to wait for the background jobs to finish 
	before timing out. 	Adjust this depending out the speed of your environment 
	and based on the maximum jobs ran simultaneously.
	
	If the MaxJobs setting is turned down, but there are a lot of servers this 
	may need to be increased.
	
	This timer starts after all jobs have been queued.
	Default = 300 (5 minutes)
.PARAMETER vCenter
	Vmware vSphere Virtual Center FQDN.
	It is used for a few minor tasks if WMI fails to for system information queries.
.PARAMETER UseAltViCreds
	This switch will trigger a be prompt to enter alternate credentials for 
	connecting to vCenter.
.PARAMETER UpdateServerURL
	Microsoft WSUS Server URL used by the remote computers.
	This is the URL clients have in their registry pointing them to the WSUS
	server.
.PARAMETER SkipOutGrid
	This switch will skip displaying the end results that uses Out-GridView.
.PARAMETER SkipAllVmware
	This switch will skip all functions that require PowerCLI.
	Currently there are only a few small tasks to gather remote computer system
	data that are used. First it will try WMI and registry queries before resorting
	to quering vCenter.
.PARAMETER SkipPolicyUpdate
	This switch will skip the task to update the computer and user policies on 
	the	remote computers.
.PARAMETER SkipSettingsReset
	This switch will skip the task to reset the Windows Update service settings 
	and re-register the remote system with the WSUS server.
.LINK
	http://wiki.bonusbits.com/main/PSScript:Test-WSUSClient
	http://wiki.bonusbits.com/main/PSModule:WindowsPatching
	http://wiki.bonusbits.com/main/HowTo:Use_WindowsPatching_PowerShell_Module_to_Automate_Patching_with_WSUS_as_the_Client_Patch_Source
	http://wiki.bonusbits.com/main/HowTo:Enable_.NET_4_Runtime_for_PowerShell_and_Other_Applications
	http://wiki.bonusbits.com/main/HowTo:Setup_PowerShell_Module
	http://wiki.bonusbits.com/main/HowTo:Enable_Remote_Signed_PowerShell_Scripts
#>

#endregion Help

#region Parameters

	[CmdletBinding()]
	Param (
		[parameter(Mandatory=$false,Position=0)][string]$ComputerName,
		[parameter(Mandatory=$false)][string]$FileName,
		[parameter(Mandatory=$false)][array]$List,
		[parameter(Mandatory=$false)][string]$vCenter,
		[parameter(Mandatory=$false)][int]$MaxJobs = '100', #Because the entire task is rather quick it's better to keep this low for overall speed.
		[parameter(Mandatory=$false)][int]$JobQueTimeout = '600', #This timer starts after all jobs have been queued.
		[parameter(Mandatory=$false)][string]$UpdateServerURL,
		[parameter(Mandatory=$false)][switch]$SkipPolicyUpdate,
		[parameter(Mandatory=$false)][switch]$SkipSettingsReset,
		[parameter(Mandatory=$false)][switch]$SkipOutGrid,
		[parameter(Mandatory=$false)][switch]$SkipAllVmware,
		[parameter(Mandatory=$false)][switch]$FileBrowser,
		[parameter(Mandatory=$false)][switch]$UseAltViCreds
	)

#endregion Parameters

	If (!$Global:WindowsPatchingDefaults) {
		. "$Global:WindowsPatchingModulePath\SubScripts\MultiFunc_Show-WPMErrors_1.0.0.ps1"
		Show-WPMDefaultsMissingError
	}

	# GET STARTING GLOBAL VARIABLE LIST
	New-Variable -Name StartupVariables -Force -Value (Get-Variable -Scope Global | Select -ExpandProperty Name)
	
	# CAPTURE CURRENT TITLE
	[string]$StartingWindowTitle = $Host.UI.RawUI.WindowTitle

	# SET VCENTER HOSTNAME IF NOT GIVEN AS PARAMETER FROM GLOBAL DEFAULT
	If (!$vCenter) {
		If ($Global:WindowsPatchingDefaults) {
			$vCenter = ($Global:WindowsPatchingDefaults.vCenter)
		}
	}
	
	# SET WSUS URL IF NOT GIVEN AS A PARAMETER FROM GLOBAL DEFAULT
	If (!$UpdateServerURL) {
		If ($Global:WindowsPatchingDefaults) {
			$UpdateServerURL = ($Global:WindowsPatchingDefaults.UpdateServerURL)
		}
	}
	
	[boolean]$filebrowserused = $false
	[string]$HostListPath = ($Global:WindowsPatchingDefaults.HostListPath)

#region Prompt: Missing Host Input

	#region Prompt: FileBrowser
	
		If ($FileBrowser.IsPresent -eq $true) {
			. "$Global:WindowsPatchingModulePath\SubScripts\Func_Get-FileName_1.0.0.ps1"
			Clear
			Write-Host 'SELECT FILE CONTAINING A LIST OF HOSTS TO PATCH.'
			Get-FileName -InitialDirectory $HostListPath -Filter "Text files (*.txt)|*.txt|Comma Delimited files (*.csv)|*.csv|All files (*.*)|*.*"
			[string]$FileName = $Global:GetFileName.FileName
			[string]$HostListFullName = $Global:GetFileName.FullName
			[boolean]$filebrowserused = $true
		}
		Else {
			[boolean]$filebrowserused = $false
		}
	
	#endregion Prompt: FileBrowser

	#region Prompt: Host Input

		If (!($FileName) -and !($ComputerName) -and !($List)) {
			[boolean]$hostinputprompt = $true
			Clear
			$promptitle = ''
			
			$message = "Please Select a Host Entry Method:`n"
			
			# HM = Host Method
			$hmc = New-Object System.Management.Automation.Host.ChoiceDescription "&ComputerName", `
			    'Enter a single hostname'

			$hmf = New-Object System.Management.Automation.Host.ChoiceDescription "&FileName", `
			    'Text file name that contains a List of ComputerNames'
			
			$hml = New-Object System.Management.Automation.Host.ChoiceDescription "&List", `
			    'Enter a List of hostnames separated by a commna without spaces'
			
			$exit = New-Object System.Management.Automation.Host.ChoiceDescription "E&xit", `
			    'Exit Script'

			$options = [System.Management.Automation.Host.ChoiceDescription[]]($hmc, $hmf, $hml, $exit)
			
			$result = $host.ui.PromptForChoice($promptitle, $message, $options, 3) 
			
			# RESET WINDOW TITLE AND BREAK IF EXIT SELECTED
			If ($result -eq 3) {
				Clear
				Break
			}
			Else {
			Switch ($result)
				{
				    0 {$hmoption = 'ComputerName'} 
				    1 {$hmoption = 'FileName'}
					2 {$hmoption = 'List'}
				}
			}
			Clear
			
			# PROMPT FOR COMPUTER NAME
			If ($hmoption -eq 'ComputerName') {
				Do {
					Do {
						Clear
						Write-Host ''
	#					Write-Host 'Short name of a single host.'
						$ComputerName = $(Read-Host -Prompt 'ENTER COMPUTERNAME')
					}
					Until ($ComputerName)
					
					If ((Test-Connection -ComputerName $ComputerName -Count 2 -Quiet) -eq $true) {
						[boolean]$pinggood = $true
					}
					Else {
						[boolean]$pinggood = $false
						Write-Host ''
						Write-Host "ERROR: Ping Failed to ($ComputerName)" -ForegroundColor White -BackgroundColor Red
						Write-Host ''
						$title = ''
						$message = 'CONTINUE WITH NON PINGABLE HOST?'

						$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
						    'Continue with patching even though host is not pingable.'

						$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
						    'Stop the script.'

						$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)

						$result = $host.ui.PromptForChoice($title, $message, $options, 1) 

						switch ($result)
						{
						    0 {[boolean]$keepgoing = $true} 
						    1 {[boolean]$keepgoing = $false} 
						}
						If ($keepgoing -eq $true) {
							[boolean]$pinggood = $true
						}
					}
				}
				Until ($pinggood -eq $true)
			}
			# PROMPT FOR FileName
			Elseif ($hmoption -eq 'FileName') {
				. "$Global:WindowsPatchingModulePath\SubScripts\Func_Get-FileName_1.0.0.ps1"
				Clear
				Write-Host ''
				Write-Host 'SELECT FILE CONTAINING A LIST OF HOSTS TO PATCH.'
	#			$FileName = $(Read-Host -Prompt 'Enter File Name')
				Get-FileName -InitialDirectory $HostListPath -Filter "Text files (*.txt)|*.txt|Comma Delimited files (*.csv)|*.csv|All files (*.*)|*.*"
				[string]$FileName = $Global:GetFileName.FileName
				[string]$HostListFullName = $Global:GetFileName.FullName
				[boolean]$filebrowserused = $true
			}
			# PROMPT FOR List 
			Elseif ($hmoption -eq 'List') {
				Write-Host 'Enter a List of hostnames separated by a comma without spaces to patch.'
				$commaList = $(Read-Host -Prompt 'Enter List')
				# Read-Host only returns String values, so need to split up the hostnames and put into array
				[array]$List = $commaList.Split(',')
			}
			Else {
				Write-Host 'ERROR: Host method entry issue'
				Break
			}
		}
		
	#endregion Prompt: Host Input
		
	#region Prompt: GPO Update

		If ($hostinputprompt -eq $true) {
			Clear
			$title = ""
			$message = "PERFORM A GPO UPDATE ON CLIENTS?"

			$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
			    "Selecing yes will update the AD Group Policies on the ComputerNames."

			$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
			    "Selecting no will skip updating the AD Group Policies on the ComputerNames"

			$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)

			$result = $host.ui.PromptForChoice($title, $message, $options, 0) 

			switch ($result)
			{
			    0 {[switch]$SkipPolicyUpdate = $false} 
			    1 {[switch]$SkipPolicyUpdate = $true} 
			}
		}

	#endregion Prompt: GPO Update

	#region Prompt: Reset Client WU Settings

		If ($hostinputprompt -eq $true) {
			Clear
			$title = ""
			$message = "RESET WINDOWS UPDATE SETTINGS ON CLIENTS?"

			$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
			    "Copy batch file to ComputerName and run to reset reg settings, start/stop service, reauth and trigger detect"

			$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
			    "Do not run Reset-WUSettings.cmd on the Host List"

			$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)

			$result = $host.ui.PromptForChoice($title, $message, $options, 0) 

			switch ($result)
			{
			    0 {[switch]$SkipSettingsReset = $false} 
			    1 {[switch]$SkipSettingsReset = $true} 
			}
		}

	#endregion Prompt: Reset Client WU Settings

	#region Prompt: Vmware
	
		#region Prompt: Skip All Vmware Tasks
			
			If (($SkipAllVmware.IsPresent -eq $false) -and ($hostinputprompt -eq $true)) {
				Clear
				$title = ''
				$message = 'SKIP ALL VMWARE TASKS?'

				$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
				    'Do not use PowerCLI and vCenter for any tasks.'

				$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
				    'Use PowerCLI and vCenter for specific takss.'
						
				$exit = New-Object System.Management.Automation.Host.ChoiceDescription "E&xit", `
					'Exit Script'

				$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $exit)

				$result = $host.ui.PromptForChoice($title, $message, $options, 1) 

				# RESET WINDOW TITLE AND BREAK IF EXIT SELECTED
				If ($result -eq 2) {
					Clear
					Break
				}

				switch ($result)
				{
				    0 {[switch]$SkipAllVmware = $true} 
				    1 {[switch]$SkipAllVmware = $false} 
				}
			}

		#endregion Prompt: Skip All Vmware Tasks

		If (($SkipAllVmware.IsPresent -eq $false) -and ($hostinputprompt -eq $true)) {
		
			#region Prompt: vCenter

				If (($vCenter -eq '') -or ($vCenter -eq $null)) {
					Do {
						Clear
						$vCenter = $(Read-Host -Prompt 'ENTER vCENTER or ESX HOSTNAME')
						
						If ((Test-Connection -ComputerName $vCenter -Count 2 -Quiet) -eq $true) {
							[boolean]$pinggood = $true
						}
						Else {
							[boolean]$pinggood = $false
							Write-Host ''
							Write-Host "ERROR: Ping Failed to ($vCenter)" -ForegroundColor White -BackgroundColor Red
							Write-Host ''
							$title = ''
							$message = 'CONTINUE WITH NON PINGABLE HOST?'

							$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
							    'Continue with patching even though host is not pingable.'

							$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
							    'Stop the script.'

							$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)

							$result = $host.ui.PromptForChoice($title, $message, $options, 1) 

							switch ($result)
							{
							    0 {[boolean]$keepgoing = $true} 
							    1 {[boolean]$keepgoing = $false} 
							}
							If ($keepgoing -eq $true) {
								[boolean]$pinggood = $true
							}
						}
					}
					Until ($pinggood -eq $true)
				} #IF vCenter doesn't have a value

			#endregion Prompt: vCenter

			#region Prompt: Alternate VIM Credentials

				Clear
				$title = ''
				$message = 'ENTER ALTERNATE VIM CREDENTIALS?'
			
				$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
				    'Enter UserName and password for vCenter access instead of using current credintials.'
			
				$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
				    'Do not enter UserName and password for vCenter access. Just use current.'
			
				$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
			
				$result = $host.ui.PromptForChoice($title, $message, $options, 1) 
			
				switch ($result)
				{
				    0 {[switch]$UseAltViCreds = $true} 
				    1 {[switch]$UseAltViCreds = $false} 
				}
				
			#endregion Prompt: Alternate VIM Credentials

		}

	#endregion Prompt: Vmware


#endregion Prompt: Missing Host Input

#region Prompt: Get Alt VI Credentials

		# Prompt for ViCreds if needed
		If ($UseAltViCreds.IsPresent -eq $true) {
			Do {
				Try {
					$ViCreds = Get-Credential -ErrorAction Stop
					[boolean]$getcredssuccess = $true
				}
				Catch {
					[boolean]$getcredssuccess = $false
				}
			}
			Until ($getcredssuccess -eq $true)
		}
		# If -AltViCreds switch is present then prompt for Alternate Credentials for vCenter
		ElseIf ($UseAltViCreds.IsPresent -eq $true) {
				Write-Host ''
				$ViCreds = Get-Credential
		}

#endregion Prompt: Get Alt VI Credentials

#region Variables

	# DEBUG
	$ErrorActionPreference = "Inquire"
	
	# SET ERROR MAX LIMIT
	$MaximumErrorCount = '1000'
	$Error.Clear()

	# SCRIPT INFO
	[string]$ScriptVersion = '2.4.3'
	[string]$ScriptTitle = "Test WSUS Client Setting by Levon Becker"
	[int]$DashCount = '40'

	# CLEAR VARIABLES
	[int]$TotalHosts = 0

	# LOCALHOST
	[string]$ScriptHost = $Env:COMPUTERNAME
	[string]$UserDomain = $Env:USERDOMAIN
	[string]$UserName = $Env:USERNAME
	[string]$FileDateTime = Get-Date -UFormat "%Y-%m%-%d_%H.%M"
	[datetime]$ScriptStartTime = Get-Date
	$ScriptStartTimeF = Get-Date -Format g

	# DIRECTORY PATHS
	[string]$LogPath = ($Global:WindowsPatchingDefaults.TCLogPath)
	[string]$ScriptLogPath = Join-Path -Path $LogPath -ChildPath 'ScriptLogs'
	[string]$JobLogPath = Join-Path -Path $LogPath -ChildPath 'JobData'
	[string]$ResultsPath = ($Global:WindowsPatchingDefaults.TCResultsPath)
	
	[string]$ModuleRootPath = $Global:WindowsPatchingModulePath
	[string]$SubScripts = Join-Path -Path $ModuleRootPath -ChildPath 'SubScripts'
	[string]$Assets = Join-Path -Path $ModuleRootPath -ChildPath 'Assets'
	
	# CONVERT SWITCH TO BOOLEAN TO PASS AS ARGUMENT
	[boolean]$UseAltViCredsBool = ($UseAltViCreds.IsPresent)

	#region  Set Logfile Name + Create HostList Array
	
		If ($ComputerName) {
			[string]$f = $ComputerName.ToUpper()
			# Inputitem is also used at end for Outgrid
			[string]$InputItem = $ComputerName.ToUpper() #needed so the WinTitle will be uppercase
			[array]$HostList = $ComputerName.ToUpper()
		}
		ElseIf ($FileName) {
			[string]$f = $FileName
			[string]$HostListFileName = $FileName
			# Inputitem used for WinTitle and Out-GridView Title at end
			[string]$InputItem = $FileName
			If ($filebrowserused -eq $false) {
				[string]$HostListFullName = Join-Path -Path $HostListPath -ChildPath $FileName
			}
			If ((Test-Path -Path $HostListFullName) -ne $true) {
					Write-Host ''
					Write-Host "ERROR: INPUT FILE NOT FOUND ($HostListFullName)" -ForegroundColor White -BackgroundColor Red
					Write-Host ''
					Break
			}
			[array]$HostList = Get-Content $HostListFullName
			[array]$HostList = $HostList | ForEach-Object {$_.ToUpper()}
		}
		ElseIF ($List) {
			[array]$List = $List | ForEach-Object {$_.ToUpper()}
			[string]$f = "LIST - " + ($List | Select -First 2) + " ..."
			[string]$InputItem = "LIST: " + ($List | Select -First 2) + " ..."
			[array]$HostList = $List
		}
		Else {
			Write-Host ''
			Write-Host "ERROR: INPUT METHOD NOT FOUND" -ForegroundColor White -BackgroundColor Red
			Write-Host ''
			Break
		}
		# Remove Duplicates in Array + Get Host Count
		[array]$HostList = $HostList | Select -Unique
		[int]$TotalHosts = $HostList.Count
	
	#endregion Set Logfile Name + Create HostList Array
	
	#region Determine TimeZone
	
		. "$SubScripts\Func_Get-TimeZone_1.0.0.ps1"
		Get-TimeZone -ComputerName 'Localhost'
		
		If (($Global:GetTimeZone.Success -eq $true) -and ($Global:GetTimeZone.ShortForm -ne '')) {
			[string]$TimeZone = "_" + $Global:GetTimeZone.ShortForm
		}
		Else {
			[string]$Timezone = ''
		}
	
	#endregion Determine TimeZone

	# FILENAMES
	[string]$ResultsTextFileName = "Test-WSUSClient_Results_" + $FileDateTime + $Timezone + "_($f).log"
	[string]$ResultsCSVFileName = "Test-WSUSClient_Results_" + $FileDateTime + $Timezone + "_($f).csv"
	[string]$JobLogFileName = "JobData_" + $FileDateTime + $Timezone + "_($f).log"

	# PATH + FILENAMES
	[string]$ResultsTextFullName = Join-Path -Path $ResultsPath -ChildPath $ResultsTextFileName
	[string]$ResultsCSVFullName = Join-Path -Path $ResultsPath -ChildPath $ResultsCSVFileName
	[string]$JobLogFullName = Join-Path -Path $JobLogPath -ChildPath $JobLogFileName


#endregion Variables

#region Check Dependencies
	
	[int]$depmissing = 0
	$depmissingList = $null
	# Create Array of Paths to Dependancies to check
	CLEAR
	$depList = @(
		"$SubScripts\Func_Get-Runtime_1.0.3.ps1",
		"$SubScripts\Func_Remove-Jobs_1.0.5.ps1",
		"$SubScripts\Func_Get-JobCount_1.0.3.ps1",
		"$SubScripts\Func_Get-HostDomain_1.0.2.ps1",
		"$SubScripts\Func_Get-HostIP_1.0.5.ps1",
		"$SubScripts\Func_Get-OSVersion_1.0.9.ps1",
		"$SubScripts\Func_Get-TimeZone_1.0.0.ps1",
		"$SubScripts\Func_Get-WUInfo_1.0.2.ps1",
		"$SubScripts\Func_Watch-Jobs_1.0.3.ps1",
		"$SubScripts\Func_Invoke-PSExec_1.0.7.ps1",
		"$SubScripts\Func_Reset-WPMUI_1.0.2.ps1",
		"$SubScripts\Func_Show-ScriptHeader_1.0.2.ps1",
		"$SubScripts\Func_Test-Connections_1.0.6.ps1",
		"$SubScripts\Func_Test-Permissions_1.1.0.ps1",
		"$SubScripts\MultiFunc_Set-WinTitle_1.0.5.ps1",
		"$SubScripts\MultiFunc_Out-ScriptLog_1.0.3.ps1",
		"$SubScripts\MultiFunc_Show-Script-Status_1.0.3.ps1",
		"$SubScripts\Reset-WUAService_1.0.0.cmd",
		"$LogPath",
		"$LogPath\History",
		"$LogPath\JobData",
		"$LogPath\Latest",
		"$LogPath\WIP",
		"$HostListPath",
		"$ResultsPath",
		"$SubScripts",
		"$Assets"
	)

	Foreach ($deps in $depList) {
		[boolean]$checkpath = $false
		$checkpath = Test-Path -Path $deps -ErrorAction SilentlyContinue 
		If ($checkpath -eq $false) {
			$depmissingList += @($deps)
			$depmissing++
		}
	}
	If ($depmissing -gt 0) {
		Write-Host "ERROR: Missing $depmissing Dependancies" -ForegroundColor White -BackgroundColor Red
		$depmissingList
		Write-Host ''
		Break
	}

#endregion Check Dependencies

#region Functions

	
	. "$SubScripts\Func_Get-Runtime_1.0.3.ps1"
	. "$SubScripts\Func_Remove-Jobs_1.0.5.ps1"
	. "$SubScripts\Func_Get-JobCount_1.0.3.ps1"
	. "$SubScripts\Func_Watch-Jobs_1.0.3.ps1"
	. "$SubScripts\Func_Reset-WPMUI_1.0.2.ps1"
	. "$SubScripts\Func_Show-ScriptHeader_1.0.2.ps1"
	. "$SubScripts\Func_Test-Connections_1.0.6.ps1"
	. "$SubScripts\MultiFunc_Set-WinTitle_1.0.5.ps1"
		# Set-WinTitle-Start
		# Set-WinTitle-Base
		# Set-WinTitle-Input
		# Set-WinTitle-JobCount
		# Set-WinTitle-JobTimeout
		# Set-WinTitle-Completed
	. "$SubScripts\MultiFunc_Out-ScriptLog_1.0.3.ps1"
		# Out-ScriptLog-Header
		# Out-ScriptLog-Starttime
		# Out-ScriptLog-JobTimeout
		# Out-ScriptLog-Footer
	. "$SubScripts\MultiFunc_Show-Script-Status_1.0.3.ps1"
		# Show-ScriptStatus-StartInfo
		# Show-ScriptStatus-QueuingJobs
		# Show-ScriptStatus-JobsQueued
		# Show-ScriptStatus-JobMonitoring
		# Show-ScriptStatus-JobLoopTimeout
		# Show-ScriptStatus-RuntimeTotals
	
#endregion Functions

#region Show Window Title

	Set-WinTitle-Start -title $ScriptTitle
	Show-ScriptHeader -blanklines '1' -DashCount $DashCount -ScriptTitle $ScriptTitle

#endregion Show Window Title

#region Console Start Statements
	
	Show-ScriptHeader -blanklines '4' -DashCount $DashCount -ScriptTitle $ScriptTitle
	# Get PowerShell Version with External Script
	If ($SkipAllVmware.IsPresent -eq $true) {
		Set-WinTitle-Base -ScriptVersion $ScriptVersion 
	}
	Else {
		Set-WinTitle-Base -ScriptVersion $ScriptVersion -IncludePowerCLI
	}
	[datetime]$ScriptStartTime = Get-Date
	[string]$ScriptStartTimeF = Get-Date -Format g
#	Out-ScriptLog-Starttime -StartTime $ScriptStartTimeF -ScriptLogFullName $ScriptLogFullName

#endregion Console Start Statements

#region Add ScriptLog Header

#	Out-ScriptLog-Header -ScriptLogFullName $ScriptLogFullName -ScriptHost $ScriptHost -UserDomain $UserDomain -UserName $UserName

#endregion Add ScriptLog Header

#region Update Window Title

	Set-WinTitle-Input -wintitle_base $Global:wintitle_base -InputItem $InputItem
	
#endregion Update Window Title

#region Tasks

	#region Test Connections

		Test-Connections -List $HostList -MaxJobs '25' -TestTimeout '120' -JobmonTimeout '600' -SubScripts $SubScripts -ResultsTextFullName $ResultsTextFullName -JobLogFullName $JobLogFullName -TotalHosts $TotalHosts -DashCount $DashCount -ScriptTitle $ScriptTitle -WinTitle_Input $Global:WinTitle_Input
		If ($Global:TestConnections.Success -eq $true) {
			[array]$HostList = $Global:TestConnections.PassedList
		}
		Else {
			# IF TEST CONNECTIONS SUBSCRIPT FAILS UPDATE UI AND EXIT SCRIPT
			## This is redundant, but wanted just to have some protection in place for subscript issues.
			Write-Host "`r".padright(40,' ') -NoNewline
			Write-Host "`rERROR: TEST CONNECTIONS FUNCTION FAILURE" -ForegroundColor White -BackgroundColor Red
			Write-Host ''
			Break
		}

	#endregion Test Connections

	#region Job Tasks
	
		Show-ScriptHeader -blanklines '1' -DashCount $DashCount -ScriptTitle $ScriptTitle

		# STOP AND REMOVE ANY RUNNING JOBS
		Stop-Job *
		Remove-Job *
		
		# SHOULD SHOW ZERO JOBS RUNNING
		Get-JobCount 
		Set-WinTitle-JobCount -WinTitle_Input $Global:WinTitle_Input -jobcount $Global:getjobcount.JobsRunning
	
		#Create CSV file with headers
		Add-Content -Path $ResultsTextFullName -Encoding ASCII -Value 'Hostname,Complete Success,GPO Update Success,Reset-WU Success,Connect Success,Runtime,Starttime,Endtime,Operating System,Host IP,Host Domain,Passed Reg Check,WU Server,WU Status Server,Use WU Server,GPOU ExitCode,Reset-WU ExitCode,Errors,Script Version,Admin Host,User Account'	
		
		#Add Failed Connection Systems to Results Text File
		If ($Global:TestConnections.FailedCount -gt '0') {
			Get-Runtime -StartTime $ScriptStartTime
			[string]$FailedConnectResults = 'False,False,False,False' + ',' + $Global:GetRuntime.Runtime + ',' + $ScriptStartTimeF + ',' + $Global:GetRuntime.EndTimeF + ',' + "Unknown,Unknown,Unknown,Unknown,Unknown,Unknown,Error,Failed Connection" + ',' + $ScriptVersion + ',' + $ScriptHost + ',' + $UserName
			$Global:TestConnections.FailedList | Foreach-Object {Add-Content -Path $ResultsTextFullName -Encoding ASCII -Value ($_ + ',' + $FailedConnectResults)}
		}
		
		#region Job Loop
		
			[int]$hostcount = $HostList.Count
			$i = 0
			[boolean]$FirstGroup = $false
			Foreach ($ComputerName in $HostList) {
				$taskprogress = [int][Math]::Ceiling((($i / $hostcount) * 100))
				# Progress Bar
				Write-Progress -Activity "STARTING WSUS SETTINGS TEST JOB ON - ($ComputerName)" -PercentComplete $taskprogress -Status "OVERALL PROGRESS - $taskprogress%"
				
				# UPDATE COUNT AND WINTITLE
				Get-JobCount
				Set-WinTitle-JobCount -WinTitle_Input $Global:WinTitle_Input -jobcount $Global:getjobcount.JobsRunning
				# CLEANUP FINISHED JOBS
				Remove-Jobs -JobLogFullName $JobLogFullName

				#region Throttle Jobs
					
					# PAUSE FOR A FEW AFTER THE FIRST 25 ARE QUEUED
					If (($Global:getjobcount.JobsRunning -ge '20') -and ($FirstGroup -eq $false)) {
						Sleep -Seconds 5
						[boolean]$FirstGroup = $true
					}
				
					While ($Global:getjobcount.JobsRunning -ge $MaxJobs) {
						Sleep -Seconds 5
						Remove-Jobs -JobLogFullName $JobLogFullName
						Get-JobCount
						Set-WinTitle-JobCount -WinTitle_Input $Global:WinTitle_Input -jobcount $Global:getjobcount.JobsRunning
					}
				
				#endregion Throttle Jobs
				
				# Set Job Start Time Used for Elapsed Time Calculations at End ^Needed Still?
				[string]$JobStartTime1 = Get-Date -Format g
#				Add-Content -Path $ScriptLogFullName -Encoding ASCII -Value "JOB STARTED:     ($ComputerName) $JobStartTime1"
				
				#region Background Job

					Start-Job -RunAs32 -ScriptBlock {

						#region Job Variables

							# Set Varibles from Argument List
							$ComputerName = $args[0]
							$Assets = $args[1]
							$SubScripts = $args[2]
							$JobLogFullName = $args[3] 
							$ResultsTextFullName = $args[4]
							$ScriptHost = $args[5]
							$UserDomain = $args[6]
							$UserName = $args[7]
							$SubScripts = $args[8]
							$LogPath = $args[9]
							$vCenter = $args[10]
							$ScriptVersion = $args[11]
							$SkipPolicyUpdate = $args[12]
							$SkipSettingsReset = $args[13]
							$UpdateServerURL = $args[14]
							$UseAltViCredsBool = $args[15]
							$ViCreds = $args[16]
							$SkipAllVmwareBool = $args[17]

							$testcount = 1
							
							# DATE AND TIME
							$JobStartTimeF = Get-Date -Format g
							$JobStartTime = Get-Date
							
							# NETWORK SHARES
							[string]$RemoteShareRoot = '\\' + $ComputerName + '\C$' 
							[string]$RemoteShare = Join-Path -Path $RemoteShareRoot -ChildPath 'WindowsPatching'
							
							# HISTORY LOG
							[string]$HistoryLogFileName = $ComputerName + '_TestWSUSClient_History.log' 
							[string]$LocalHistoryLogPath = Join-Path -Path $LogPath -ChildPath 'History' 
							[string]$RemoteHistoryLogPath = $RemoteShare 
							[string]$LocalHistoryLogFullName = Join-Path -Path $LocalHistoryLogPath -ChildPath $HistoryLogFileName
							[string]$RemoteHistoryLogFullName = Join-Path -Path $RemoteHistoryLogPath -ChildPath $HistoryLogFileName
														
							# LATEST LOG
							[string]$LatestLogFileName = $ComputerName + '_TestWSUSClient_Latest.log' 
							[string]$LocalLatestLogPath = Join-Path -Path $LogPath -ChildPath 'Latest' 
							[string]$RemoteLatestLogPath = $RemoteShare 
							[string]$LocalLatestLogFullName = Join-Path -Path $LocalLatestLogPath -ChildPath $LatestLogFileName 
							[string]$RemoteLatestLogFullName = Join-Path -Path $RemoteLatestLogPath -ChildPath $LatestLogFileName
							
							# TEMP WORK IN PROGRESS PATH
							[string]$WIPPath = Join-Path -Path $LogPath -ChildPath 'WIP' 
							[string]$WIPFullName = Join-Path -Path $WIPPath -ChildPath $ComputerName
							
							# SCRIPTS
							[string]$ResetWUAFileName = "Reset-WUAService_1.0.0.cmd"
							[string]$RemoteWUScript = Join-Path -Path $RemoteShare -ChildPath $ResetWUAFileName
							[string]$LocalWUScript = Join-Path -Path $SubScripts -ChildPath $ResetWUAFileName
							[string]$ResetWUARemoteCommand = 'C:\WindowsPatching\' + $ResetWUAFileName
							[string]$SeceditMachineRemoteCommand = 'secedit.exe /refreshpolicy machine_policy'
							[string]$SeceditUserRemoteCommand = 'secedit.exe /refreshpolicy user_policy'
							[string]$GpupdateRemoteCommand = 'gpupdate.exe /force'
							
							
							# SET INITIAL JOB SCOPE VARIBLES
							[boolean]$Failed = $false
							[boolean]$CompleteSuccess = $false
							[boolean]$ConnectionFailed = $false #Used?
							[string]$WuServer = 'Unknown'
							[string]$WuStatusServer = 'Unknown'
							[string]$UseWuServer = 'Unknown' # Boolean?
							[string]$OSVersionShortName = 'Unknown'
							[string]$HostIP = 'Unknown'
							[string]$HostDomain = 'Unknown'
							[Boolean]$ConnectSuccess = $true
							[string]$ScriptErrors = 'None'

						#endregion Job Variables

						#region Job Functions
						
							. "$SubScripts\Func_Get-Runtime_1.0.3.ps1"
							. "$SubScripts\Func_Get-HostDomain_1.0.2.ps1"
							. "$SubScripts\Func_Get-HostIP_1.0.5.ps1"
							. "$SubScripts\Func_Get-OSVersion_1.0.9.ps1"
							. "$SubScripts\Func_Get-WUInfo_1.0.2.ps1"
							. "$SubScripts\Func_Invoke-PSExec_1.0.7.ps1"
							. "$SubScripts\MultiFunc_Out-ScriptLog_1.0.3.ps1"
								# Out-ScriptLog-Header
								# Out-ScriptLog-Starttime
								# Out-ScriptLog-Error
								# Out-ScriptLog-JobTimeout
								# Out-ScriptLog-Footer

						#endregion Job Functions
						
						#region Start
						
							# CREATE WIP TRACKING FILE IN WIP DIRECTORY
							If ((Test-Path -Path $WIPFullName) -eq $false) {
								New-Item -Item file -Path $WIPFullName -Force | Out-Null
							}
							
							# CREATE CLIENT PATCH DIRECTORY FOR SCRIPTS IF MISSING
							If ((test-path -Path $RemoteShare) -eq $False) {
								New-Item -Path $RemoteShareRoot -name WindowsPatching -ItemType Directory -Force | Out-Null
							}
							
							#region Temp: Remove Old Remote Computer Directory
						
								If ((Test-Path -Path "$RemoteShareRoot\Windows-Patching") -eq $true) {
									If ((Test-Path -Path "$RemoteShareRoot\Windows-Patching\*.log") -eq $true) {
										Copy-Item -Path "$RemoteShareRoot\Windows-Patching\*.log" -Destination $RemoteShare -Force
									}
									Remove-Item -Path "$RemoteShareRoot\Windows-Patching" -Recurse -Force
								}
						
							#endregion Temp: Remove Old Remote Computer Directory
							
							# REMOVE OLD FILES
							$filepaths = @(
								"\\$ComputerName\c$\WindowsPatching\WUReset_1.0.0.cmd"
#								("\\$ComputerName\c$\WindowsPatching\" + $ComputerName + '_LastPatch.log')
							)
							# Remove each item in the filepaths array if exists
							ForEach ($filepath in $filepaths) {
								If ((Test-Path -Path $filepath) -eq $true) {
									Remove-Item -Path $filepath -Force 
								}
							}
						
							$OldHistoryFileFullName = '\\' + $ComputerName + '\c$\WindowsPatching\' + $ComputerName + '_WSUSCheck.log'
							If ((Test-Path -Path $OldHistoryFileFullName) -eq $true) {
								Rename-Item -Path $OldHistoryFileFullName -NewName $HistoryLogFileName -Force
							}
							
							# WRITE HISTORY LOG HEADER TO LOGARRAY
							$DateTimeF = Get-Date -format g
							$results = $null
							$ScriptLogData = @()
							$ScriptLogData += @(
								'',
								'',
								'*******************************************************************************************************************',
								'*******************************************************************************************************************',
								"JOB STARTED: $DateTimeF",
								"SCRIPT VER:  $ScriptVersion",
								"ADMINUSER:   $UserDomain\$UserName",
								"SCRIPTHOST:  $ScriptHost"
							)
							
						#endregion Start
						
						#region Get OS Version
							# ^NEED TO ADD ALTCREDS LOGIC
							If ($SkipAllVmwareBool -eq $true) {
								Get-OSVersion -ComputerName $ComputerName -SubScripts $SubScripts -SkipVimQuery
							}
							Else {
								Get-OSVersion -ComputerName $ComputerName -SubScripts $SubScripts -vCenter $vCenter
							}
							# WRITE RESULTS TO HISTORY LOGS LOGDATAARRAY
							$results = $null
							[array]$results = ($Global:GetOSVersion | Format-List | Out-String).Trim('')
							$ScriptLogData += @(
								'',
								'GET OS VERSION',
								'---------------',
								"$results"
							)
							If ($Global:GetOSVersion.Success -eq $true) {
								[string]$OSVersionShortName = $Global:GetOSVersion.OSVersionShortName
								[string]$OSArch = $Global:GetOSVersion.OSArch
								[string]$OSVersion = $Global:GetOSVersion.OSVersion
							}
							Else {
								[string]$OSVersionShortName = 'Error'
								[string]$OSArch = 'Error'
								[string]$OSVersion = 'Error'
							}
							
							
						#endregion Get OS Version
						
						#region Get Host Domain
							
							If ($SkipAllVmwareBool -eq $true) {
								Get-HostDomain -ComputerName $ComputerName -SubScripts $SubScripts -SkipVimQuery
							}
							Else {
								Get-HostDomain -ComputerName $ComputerName -SubScripts $SubScripts -vCenter $vCenter
							}
							# WRITE RESULTS TO HISTORY LOGS LOGDATAARRAY
							$results = $null
							[array]$results = ($Global:gethostdomain | Format-List | Out-String).Trim('')
							$ScriptLogData += @(
								'',
								'GET HOST DOMAIN',
								'----------------',
								"$results"
							)
							If ($Global:gethostdomain.Success -eq $true) {
								[string]$HostDomain = $Global:gethostdomain.HostDomain
							}
							Else {
								[string]$HostDomain = 'Error'
							}
							
						#endregion Get Host Domain
						
						#region Get HOST IP
							
							If ($SkipAllVmwareBool -eq $true) {
								Get-HostIP -ComputerName $ComputerName -SubScripts $SubScripts -SkipVimQuery
							}
							Else {
								Get-HostIP -ComputerName $ComputerName -vCenter $vCenter -SubScripts $SubScripts
							}
							# WRITE RESULTS TO HISTORY LOGS LOGDATAARRAY
							$results = $null
							[array]$results = ($Global:GetHostIP | Format-List | Out-String).Trim('')
							$ScriptLogData += @(
								'',
								'GET HOST IP',
								'------------',
								"$results"
							)
							If ($Global:GetHostIP.Success -eq $true) {
								[string]$HostIP = $Global:GetHostIP.HostIP
							}
							Else {
								[string]$HostIP = 'Error'
							}
							
						#endregion Get HOST IP
						
						#region Get WUInfo
							
							Get-WUInfo -ComputerName $ComputerName -SubScripts $SubScripts -Assets $Assets -UpdateServerURL $UpdateServerURL 
							If ($Global:getwuinfo.Success -eq $true) {
								[string]$WuServer = $Global:getwuinfo.WUServer
								[string]$WuStatusServer = $Global:getwuinfo.WUStatusServer
								[boolean]$PassedRegAudit = $Global:getwuinfo.WUServerOK
								[string]$UseWuServer = $Global:getwuinfo.UseWUServer
							}
							Else {
								[boolean]$Failed = $true
								[string]$WuServer = 'Error'
								[string]$WuStatusServer = 'Error'
								[string]$PassedRegAudit = 'Error'
								[string]$UseWuServer = 'Error'
							}
							# WRITE RESULTS TO HISTORY LOGS LOGDATAARRAY
							$results = $null
							[array]$results = ($Global:getwuinfo | Format-List | Out-String).Trim('')
							$ScriptLogData += @(
								'',
								'GET WINDOWS UPDATE INFO',
								'-----------------------',
								"$results"
							)

						#endregion Get WUInfo
						
						#region GPO Update

							# RUN GPO UPDATE IF SELECTED
							If ($SkipPolicyUpdate.IsPresent -eq $false) {
								# UPDATE HISTORY LOGS
								If ($Global:GetOSVersion.Success -eq $true) {
									# REFRESH GROUP POLICIES BASED ON OS
									IF (($Global:GetOSVersion.OSVersionShortName -eq '2000') -or ($Global:GetOSVersion.OSVersionShortName -eq 'XP')-or ($Global:GetOSVersion.OSVersionShortName -eq 'NT')) {
										# RUN SECEDIT ON REMOTE HOST FOR MACHINE POLICY
										Invoke-PSExec -ComputerName $ComputerName -SubScripts $SubScripts -Assets $Assets -Timeout '600' -RemoteCommand $SeceditMachineRemoteCommand
										
										# WRITE RESULTS TO HISTORY LOGS LOGDATAARRAY
										$results = $null
										[array]$results = ($Global:InvokePSExec | Format-List | Out-String).Trim('')
										$ScriptLogData += @(
											'',
											'Invoke-PSExec SECEDIT MACHINE UPDATE GPOUPDATE',
											'-------------------------------------------',
											"$results"
										)
										
										$GPOUpdateExitCode = $Global:InvokePSExec.ExitCode
										If ($Global:InvokePSExec.Success -eq $true) {
											[boolean]$GPOUpdateSuccess = $true
										}
										Else {
											[boolean]$Failed = $true
											[boolean]$GPOUpdateSuccess = $false
										}
										# RUN SECEDIT ON REMOTE HOST FOR USER POLICY
										Invoke-PSExec -ComputerName $ComputerName -SubScripts $SubScripts -Assets $Assets -Timeout '600' -RemoteCommand $SeceditUserRemoteCommand
																				
										# WRITE RESULTS TO HISTORY LOGS LOGDATAARRAY
										$results = $null
										[array]$results = ($Global:InvokePSExec | Format-List | Out-String).Trim('')
										$ScriptLogData += @(
											'',
											'Invoke-PSExec SECEDIT USER POLICY GPOUPDATE',
											'----------------------------------------',
											"$results"
										)
										
										$GPOUpdateExitCode = $Global:InvokePSExec.ExitCode
										If ($Global:InvokePSExec.Success -eq $true) {
											[boolean]$GPOUpdateSuccess = $true
										}
										Else {
											[boolean]$Failed = $true
											[boolean]$GPOUpdateSuccess = $false
										}
									}
									Else {
										# RUN GPUPDATE ON REMOTE HOST
										Invoke-PSExec -ComputerName $ComputerName -SubScripts $SubScripts -Assets $Assets -Timeout '600' -RemoteCommand $GpupdateRemoteCommand
										
										# WRITE RESULTS TO HISTORY LOGS LOGDATAARRAY
										$results = $null
										[array]$results = ($Global:InvokePSExec | Format-List | Out-String).Trim('')
										$ScriptLogData += @(
											'',
											'Invoke-PSExec GPUPDATE',
											'-------------------',
											"$results"
										)
										
										$GPOUpdateExitCode = $Global:InvokePSExec.ExitCode
										If ($Global:InvokePSExec.Success -eq $true) {
											[boolean]$GPOUpdateSuccess = $true
										}
										Else {
											[boolean]$Failed = $true
											[boolean]$GPOUpdateSuccess = $false
										}									
									}
								}
								Else {
									[boolean]$GPOUpdateSuccess = $false
								}
							}
							
						#endregion GPO Update
						
						#region WU Reset

							If ($SkipSettingsReset.IsPresent -eq $false) {
								# IF RESET-WUAService.CMD IS MISSING THEN COPY TO CLIENT
								If ((Test-Path -Path $RemoteWUScript) -eq $False) {
									Copy-Item -Path $LocalWUScript -Destination $RemoteShare | Out-Null 
								}
								
								# RESTART WINDOWS UPDATE SERVICE ON CLIENT WITH BATCH FILE
								Invoke-PSExec -ComputerName $ComputerName -SubScripts $SubScripts -Assets $Assets -Timeout '600' -RemoteCommand $ResetWUARemoteCommand
								
								# WRITE RESULTS TO HISTORY LOGS LOGDATAARRAY
								$results = $null
								[array]$results = ($Global:InvokePSExec | Format-List | Out-String).Trim('')
								$ScriptLogData += @(
									'',
									'Invoke-PSExec Run Reset-WUSettings.cmd',
									'--------------------------------------',
									"$results"
								)

								
								$ResetWUAExitCode = $Global:InvokePSExec.ExitCode
								If ($Global:InvokePSExec.Success -eq $true) {
									[boolean]$ResetWUASuccess = $true
								}
								Else {
									[boolean]$Failed = $true
									[boolean]$ResetWUASuccess = $false
								}
							} #/If WURest Option = Yes

						#endregion WU Reset
						
						#region End
						
							# REMOVE WIP OBJECT FILE
							If ((Test-Path -Path $WIPFullName) -eq $true) {
								Remove-Item -Path $WIPFullName -Force
							}
							Get-Runtime -StartTime $JobStartTime #Results used for History Log Footer too
							
							If ($Failed -eq $false) {
								[boolean]$CompleteSuccess = $true
							}
							Else {
								[boolean]$CompleteSuccess = $false
							}
							If ($Global:GetOSVersion.Success -eq $true) {
								[string]$OSVersion = $Global:GetOSVersion.OSVersion
							}
							Else {
								[string]$OSVersion = 'Unknown'
							}
							
							If (!$ScriptErrors) {
								[string]$ScriptErrors = 'None'
							}
							
							[string]$TaskResults = $ComputerName + ',' + $CompleteSuccess + ',' + $GPOUpdateSuccess + ',' + $ResetWUASuccess + ',' + $ConnectSuccess + ',' + $Global:GetRuntime.Runtime + ',' + $JobStartTimeF + ',' + $Global:GetRuntime.EndTimeF + ',' + $OSVersion + ',' + $HostIP + ',' + $HostDomain + ',' + $PassedRegAudit + ',' + $WuServer + ',' + $WuStatusServer + ',' + $UseWuServer + ',' + $GPOUpdateExitCode + ',' + $ResetWUAExitCode + ',' + $ScriptErrors + ',' + $ScriptVersion + ',' + $ScriptHost + ',' + $UserName
							
							[int]$loopcount = 0
							[boolean]$errorfree = $false
							DO {
								$loopcount++
								Try {
									Add-Content -Path $ResultsTextFullName -Encoding Ascii -Value $TaskResults -ErrorAction Stop
									[boolean]$errorfree = $true
								}
								# IF FILE BEING ACCESSED BY ANOTHER SCRIPT CATCH THE TERMINATING ERROR
								Catch [System.IO.IOException] {
									[boolean]$errorfree = $false
									Sleep -Milliseconds 500
									# Could write to ScriptLog which error is caught
								}
								# ANY OTHER EXCEPTION
								Catch {
									[boolean]$errorfree = $false
									Sleep -Milliseconds 500
									# Could write to ScriptLog which error is caught
								}
							}
							# Try until writes to output file or 
							Until (($errorfree -eq $true) -or ($loopcount -ge '150'))
							
							# History Log Footer
							$Runtime = $Global:GetRuntime.Runtime
							$DateTimeF = Get-Date -format g
							$ScriptLogData += @(
								'',
								'',
								'',
								"COMPLETE SUCCESS: $CompleteSuccess",
								'',
								"JOB:             [ENDED] $DateTimeF",
								"Runtime:         $Runtime",
								'---------------------------------------------------------------------------------------------------------------------------------',
								''
							)
							# Write LogDataArray to History Logs
							Add-Content -Path $LocalHistoryLogFullName,$RemoteHistoryLogFullName -Encoding ASCII -Value $ScriptLogData
							Out-File -FilePath $LocalLatestLogFullName -Encoding ASCII -Force -InputObject $ScriptLogData
							Out-File -FilePath $RemoteLatestLogFullName -Encoding ASCII -Force -InputObject $ScriptLogData
						
						#endregion End

					} -ArgumentList $ComputerName,$Assets,$SubScripts,$JobLogFullName,$ResultsTextFullName,$ScriptHost,$UserDomain,$UserName,$SubScripts,$LogPath,$vCenter,$ScriptVersion,$SkipPolicyUpdate,$SkipSettingsReset,$UpdateServerURL,$UseAltViCredsBool,$ViCreds,$SkipAllVmwareBool | Out-Null
					
				#endregion Background Job
				
				# PROGRESS COUNTER
				$i++
			} #/Foreach Loop
		
		#endregion Job Loop

		Show-ScriptHeader -blanklines '4' -DashCount $DashCount -ScriptTitle $ScriptTitle
		Show-ScriptStatus-JobsQueued -jobcount $Global:TestConnections.PassedCount
		
	#endregion Job Tasks

	#region Job Monitor

		Get-JobCount
		Set-WinTitle-JobCount -WinTitle_Input $Global:WinTitle_Input -jobcount $Global:getjobcount.JobsRunning
		
		# Job Monitoring Function Will Loop Until Timeout or All are Completed
		Watch-Jobs -SubScripts $SubScripts -JobLogFullName $JobLogFullName -Timeout $JobQueTimeout -Activity "TESTING WSUS SETTINGS" -WinTitle_Input $Global:WinTitle_Input
		
	#endregion Job Monitor

#endregion Tasks

#region Convert Output Text File to CSV
	
	# Import text file as CSV formated variable - Used for outgrid and CSV file creation
	$outfile = Import-Csv -Delimiter ',' -Path $ResultsTextFullName
	# Create CSV file with CSV formated variable
	$outfile | Export-Csv -Path $ResultsCSVFullName -NoTypeInformation
	# Delete text file if CSV file was created successfully
	If ((Test-Path -Path $ResultsCSVFullName) -eq $true) {
		Remove-Item -Path $ResultsTextFullName -Force
	}

#endregion Convert Output Text File to CSV

#region Script Completion Updates

	Show-ScriptHeader -blanklines '1' -DashCount $DashCount -ScriptTitle $ScriptTitle
	Get-Runtime -StartTime $ScriptStartTime
	Show-ScriptStatus-RuntimeTotals -StartTimeF $ScriptStartTimeF -EndTimeF $Global:GetRuntime.EndTimeF -Runtime $Global:GetRuntime.Runtime
	[int]$TotalHosts = $Global:TestPermissions.PassedCount
	Show-ScriptStatus-TotalHosts -TotalHosts $TotalHosts
	Show-ScriptStatus-Files -ResultsPath $ResultsPath -ResultsFileName $ResultsCSVFileName -LogPath $LogPath
	
	# WRITE ERRORS TO SCRIPTLOG
#	If ($Error) {
#		Out-Script-Errors -ScriptLogFullName $ScriptLogFullName -Errors $Error
#	}
	
	If ($Global:WatchJobs.JobTimeOut -eq $true) {
#		Out-ScriptLog-JobTimeout -ScriptLogFullName $ScriptLogFullName -JobmonNotes $Global:WatchJobs.Notes -EndTime $Global:GetRuntime.Endtime -Runtime $Global:GetRuntime.Runtime
		Show-ScriptStatus-JobLoopTimeout
		Set-WinTitle-JobTimeout -WinTitle_Input $Global:WinTitle_Input
		
		# Cleanup WIP Files
		Foreach ($ComputerName in $HostList) {
			[string]$WIPPath = Join-Path -Path $LogPath -ChildPath 'WIP' 
			[string]$WIPFullName = Join-Path -Path $WIPPath -ChildPath $ComputerName
			If ((Test-Path -Path $WIPFullName) -eq $true) {
				Remove-Item -Path $WIPFullName -Force
			}
		}
	}
	Else {
#		Out-ScriptLog-Footer -EndTime $Global:GetRuntime.Endtime -Runtime $Global:GetRuntime.Runtime -ScriptLogFullName $ScriptLogFullName
		Show-ScriptStatus-Completed
		Set-WinTitle-Completed -WinTitle_Input $Global:WinTitle_Input
	}

#endregion Script Completion Updates

#region Display Report
	
	If ($SkipOutGrid.IsPresent -eq $false) {
		$outfile | Out-GridView -Title "Test WSUS Client Results for $InputItem"
	}
	
#endregion Display Report

#region Cleanup UI

	Reset-WPMUI -StartingWindowTitle $StartingWindowTitle -StartupVariables $StartupVariables -SubScripts $SubScripts
	
#endregion Cleanup UI

}

#region Notes

<# Dependents
#>

<# Dependencies
	Func_Get-Runtime
	Func_Remove-Jobs
	Func_Get-JobCount
	Func_Get-HostDomain
	Func_Get-HostIP
	Func_Get-WUInfo
	Func_Watch-Jobs
	Func_Invoke-PSExec
	Func_Reset-WPMUI
	Func_Show-ScriptHeader
	MultiFunc_StopWatch
	Func_Test-Connections
	MultiFunc_Set-WinTitle
	MultiFunc_Out-ScriptLog
	MultiFunc_Show-Script-Status
	Reset-WUSettings.cmd
#>

<# TO DO
	1. Fix up and improve script and job logging
	2. Rewrite Reset-WUSettings.cmd logic
	3. Added error handling to GPO Update and WU Reset
#>

<# Change Log
2.0.3 - 01/31/2012
	Created.
	Complete rewrite to new format
2.0.4 - 02/01/2012
	Stable
2.0.5 - 02/01/2012
	Added missing failed varible set to false to fix complete success output
	Added HostDomain subscript and sections
	Moved OS Version and HostIP var set right after running functions
2.0.6 - 02/01/2012
	Fixed order for Runtime, Startime to be correct on output.
2.0.7 - 02/01/2012
	Changed HostIP out to logs variable to correct one (Copy/Paste error)
2.0.8 - 02/02/2012
	Added missing WIP file removal to end of job loop
2.0.9 - 02/02/2012
	Converted Test Permissions Section to Subscript Function
2.1.0 - 02/02/2012
	Tweaks with Test-Connections parameters
2.1.1 - 02/02/2012
	Bumped MaxJobs for Test-Connections to 100
	Bumped MaxJobs for parent script to 200
2.1.2 - 02/03/2012
	Bumped MaxJobs for Test-Connections to 500
	Added separater Line with Header of History Logs
2.1.3 - 02/03/2012
	Changed Failedlog to FailedAccessLog
2.1.4 - 02/03/2012
	Found a limit of about 250 background jobs.
	Going to try and add some sleep and slow down the job creations to see if it can
	do more if fed slower.
2.1.5 - 02/03/2012
	Added Try/Catch to Output file in Job Loop incase file is locked by other job writing to it
2.1.6 - 02/04/2012
	Fixed mix up of currenthost and ScriptHost
	Fixed JobTimeOut Out-ScriptLog-JobTimeout parameters
	Update to MultiFunc_Out-ScriptLog_1.0.2
	Fixed issue if using List as input. Basically limited the Wintitle and filename to two hosts 
	from the List.
2.1.7 - 02/04/2012
	Combined Timeout and Completed at end so CSV is generated either way.
	Increased Monitor Jobs Timeout to 15 minutes.
	Increased MaxJobs to 1000
	Increased MaxJobs for Test-connections to 500
2.1.8 - 02/07/2012
	Updated to MultiFunc_Set-WinTitle_1.0.3
	Added dotnetversion Set-WinTitle-Base
	Changed parameter from psver to psversion for Set-WinTitle-Base
	Added spaces at end of Show-ScriptHeader so the new Progress Bars doesn't cover up the UI updates
	Changed Set-WinTitle-Notice to Set-WinTitle-Start
	Added .ToUpper() for $ComputerName filename set
2.1.9 - 02/08/2012
	Added $ErrorActionPreference = "Inquire" temp for debugging missed error handling
	Working on error handling and validaiton for PSExec
2.2.0 - 02/08/2012
	Changed GPOUPDATE section to use batch file
2.2.1 - 02/09/2012
	Adding GPUPDATE.cmd and SECRESET.cmd
2.2.2 - 02/09/2012
	Changed OSVersionShortName variable from local to global Get-OSVersion PSObject Output
2.2.3 - 02/09/2012 (Stable)
	Removed GPUPDATE_1.cmd and SECRESET_1.cmd
	Updated to Func_Invoke-PSExec_1.0.3
	Fixed up GPOUpdate section to match Invoke-PSExec 1.0.3
2.2.4 - 02/09/2012
	Converted RegAudit section to used Func_Get-WUInfo_1.0.0
2.2.5 - 02/09/2012
	Cleaned up code
	Changed WUReset_1.cmd back to WUReset.cmd
2.2.6 - 02/10/2012
	Updated to Func_Invoke-PSExec_1.0.4
2.2.6 - 02/10/2012
	Updated to Func_Invoke-PSExec_1.0.5 (Try/Catch)
	Added datetime to some history log updates
2.2.9 - 04/16/2012
	Changed Version Scheme
	Changed log file formatting
	Added Func_Show-ScriptHeader
	Changed Show-ScriptHeader lines to have parameters for Function
2.3.0 - 04/20/2012
	Switched to Fun_Invoke-PSExec_1.0.6 for parameter name changes
	Switched to Func_Get-WUInfo_1.0.1
2.3.1 - 04/20/2012
	Added Progress Bar for Queing Jobs
2.3.2 - 04/23/2012
	Tons more renames and case changes
	Changed to latest SubScripts
	Changed all the History logging to be stored in an array and output to the files once at the end.
2.3.3 - 04/26/2012
	Changed to Function and placed in WindowsPatching Module
	Several sub script renames
	Added cleanup to end
2.3.4 - 04/27/2012
	Changed Cleanup Section to Reset-WPMUI subscript.
	Added SkipGrid switch parameter
2.3.6 - 05/02/2012
	Added FileBrowser option
2.3.7 - 05/03/2012
	Changed folder locations and some names using Set-WindowsPatchingDefault Global variable.
	Changed Windows-Patching to WindowsPatching remote folder
	Added remove / copy logs of Windows-Patching folder on remote system
	Renamed a lot of variables so they make more since and continued improvement on my own stardards
	Fixed some rename mistakes
	Changed Set-Header to Show-ScriptHeader
	Added Out-ScriptLog-Errors specifically for writing $Error to log, may not need it
	Added Show-ScriptStatus-Files function to give path to output files and folders
	Changed name of WUReset.cmd to WUReset_1.0.0.cmd
2.3.8 - 05/07/2012
	Renamed Get-FileName to Func_Get-FileName and moved to SubScripts
	Changed the module to not load Get-FileName and have the scripts call it if needed.
	Moved GPO Success and WUReset Success to front of results
2.3.9 - 05/08/2012
	Fixed Get-OSVersion Function load to correct version 1.0.8
	Added Logic for the SkipAllVmware for Get-OSVersion
	Added Logic for the SkipAllVmware for Get-HostDomain
	Added Logic for the SkipAllVmware for Get-HostIP
	Added JobQueTimeout parameter
	Turned down MaxJobs default. having issues with over 500 currently.
	Tweaked the Maxjobs and JobQueTimeouts to be more efficient
	Added Remove-Jobs to each loop to maintain a better Jobs Left nummber and stay out of the Job Throttle loop more.
	Added WIP file cleanup for it Watch-Jobs Timeout.
	Switched to Test-Connections 1.0.4
	Switched to Watch-Jobs 1.0.3
	Added Get-TimeZone to pull localhost timezone for file names.
2.4.0 - 05/10/2012
	Renamed Reset-UI to Reset-WPMUI
	Added vCenter and Alt VIM Creds Prompts
	Added missing SkipAllVmware logic to job
2.4.1 - 05/11/2012
	Fixed Prompt for AltViCreds. It needed to be outside Missing Host Vmware Prompt Group.
2.4.2 - 05/14/2012
	Switched to Show-WPMTip 1.0.2
2.4.2 - 05/15/2012
	Added Hosts that failed connection test to Results.
	Added Latest Log output
	Renamed History Log
	Renamed WUReset to Reset-WUSettings
	Renamed more variables with upper and lower case
2.4.3 - 05/16/2012
	Switched to Get-OSVersion 1.0.9
	Removed FailedAccess logic now that it's in the results.
	Switched to Test-Connections 1.0.6
#>


#endregion Notes
